#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "ClosedObject.h"
#include "GL/glut.h"
#include "include.h"

ClosedObject::ClosedObject(TextureManager * textureManager, float textureRotation, Vertex position, VertexList * vertices, Material * material, float mass)
:Object(textureManager, vertices)
{
	this->mass = mass;
	this->textureRotation = textureRotation;
	this->position = position;
	printf("Making vertex list\n");
	printf("Position = (%f, %f)\n", this->position.GetPosition().x, this->position.GetPosition().y);
	textureVertices = NULL;
	if(material)
		printf("material name = %s\n", material->name);
	else
		printf("Arrghh!!\n");
	SetMaterial(material);	
	CreatePropertyMenu();
	propertyMenu->Hide();
	printf("done making closed object\n");
}
ClosedObject::ClosedObject(TextureManager * textureManager, Vertex position)
:Object(textureManager, NULL)
{
	this->position = position;
	printf("Making vertex list\n");
	printf("Position = (%f, %f)\n", this->position.GetPosition().x, this->position.GetPosition().y);
	vertices = new VertexList();
	vertices->Add(new Vertex(this->position.GetPosition() + Vector2D(-2,2)));
	vertices->Add(new Vertex(this->position.GetPosition() + Vector2D(2,2)));
	vertices->Add(new Vertex(this->position.GetPosition() + Vector2D(2,-2)));
	vertices->Add(new Vertex(this->position.GetPosition() + Vector2D(-2,-2)));
	textureVertices = NULL;
	CreatePropertyMenu();
	propertyMenu->Hide();
}
void ClosedObject::ViewProperties()
{
	propertyMenu->Show();
}
void ClosedObject::HideProperties()
{
	propertyMenu->Hide();
}
void ClosedObject::CreatePropertyMenu()
{
	printf("ClosedObject::CreatePropertyMenu\n");
	propertyMenu = new FormMenu(textureManager, "1,Mass,1", PROPERTY_MENU_POSITION, 0);
	float massCheck = mass;
	int size = 0;
	while(massCheck > 1)
	{
		size++;
		massCheck /= 10;
	}
	size += 6;
	char * massString = (char*)malloc(sizeof(char)*size);
	sprintf(massString, "%.3f", mass);
	propertyMenu->SetFormContent(0,massString);
}
ClosedObject::ClosedObject(TextureManager * textureManager, Vertex position, VertexList * vertices)
: Object(textureManager, vertices)
{
	this->position = position;
	textureVertices = NULL;
	CreatePropertyMenu();
	propertyMenu->Hide();
}

ClosedObject::~ClosedObject()
{
	
}

void ClosedObject::RemoveVertex(Vertex * vertex)
{
	if(!vertices || vertices->GetLength() <= 3)
		return;
	vertices->Remove(vertex);
}
void ClosedObject::DrawEntryPoint()
{
	
}
void ClosedObject::Draw()
{
	if(vertices)
		vertices->Draw();
	position.Draw();
	
	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glAlphaFunc( GL_GREATER, 0.01 );
	glEnable( GL_ALPHA_TEST );
	glEnable(GL_BLEND);	
	
	
	if(vertices &&  vertices->head && vertices->tail)
	{
		glBegin(GL_LINES);
		glVertex2f(vertices->head->payload->GetPosition().x, vertices->head->payload->GetPosition().y);
		glVertex2f(vertices->tail->payload->GetPosition().x, vertices->tail->payload->GetPosition().y);	
		glEnd();
	}
	
	DrawEntryPoint();
	//draw the closed shape
	if(textureIndex >= 0)
	{
		TexturedDraw();
	}
	else
	{
		if(activeObject)
			glColor4f(0.0, 1.0, 0.0, 0.8);
		else
			glColor4f(0.0,1.0,0.0,0.4);
			
			
		
		glBegin(GL_POLYGON);
		List<Vertex> * search = vertices->head;
		while(search)
		{
			if(search->payload)
				glVertex2f(search->payload->GetPosition().x,search->payload->GetPosition().y);
			search = search->next;
		}
		glEnd();
	}
	glDisable(GL_BLEND);
}
void ClosedObject::RotateTexture(float theta)
{
	textureRotation += theta;
	while(textureRotation > 2*PI)
		textureRotation -= 2*PI;
	while(textureRotation < 0)
		textureRotation += 2*PI;
	CalculateTextureVertices(theta);
}
void ClosedObject::CalculateTextureVertices(float theta)
{
	//printf("Object::CalculateTextureVertices numVertices = %d\n", numVertices);
	
	if(!textureVertices)
	{
		if(!vertices || vertices->GetLength() <= 0)
			return;
		textureVertices = (Vector2D*)malloc(sizeof(Vector2D)*vertices->GetLength());
		List<Vertex> * search = vertices->head;
		int i = 0;
		while(search)
		{
			
			textureVertices[i] = (search->payload->GetPosition() - GetRotationPoint());
			if(material)
				textureVertices[i] *= material->size;
			printf("textureVetices[%d] = (%f, %f)\n", i, textureVertices[i].x, textureVertices[i].y);
			i++;
			search = search->next;
		}
		
	}
	float sinTheta = sin(theta);
	float cosTheta = cos(theta);
	
	printf("vertices length = %d\n", vertices->GetLength());
	for(int i = 0; i < vertices->GetLength(); i++)
	{
		Vector2D vertex = textureVertices[i];
		float newX = vertex.x * cosTheta - vertex.y * sinTheta;
		float newY = vertex.y * cosTheta + vertex.x * sinTheta;
		printf("old = (%f, %f)\n", textureVertices[i].x, textureVertices[i].y);
		printf("new = (%f, %f)\n", newX, newY);
		//float size = 0.1;
		//if(material)
		//	size = material->size;
		textureVertices[i].x = newX;
		textureVertices[i].y = newY;
	}	
}
void ClosedObject::SetMaterial(Material * material)
{
	printf("Setting material\n");
	this->material = material;
	if(textureManager && material)
	{
		if(!textureManager->LoadTexture(material->fileName))
		{
			printf("Failed to load %s\n", material->fileName);	
		}
		else
			textureIndex = textureManager->TextureIndex(material->fileName);
	}
	else
		textureIndex = -1;
		
	printf("new texture index = %d\n", textureIndex);
	CalculateTextureVertices(textureRotation);
	printf("done\n");
}
void ClosedObject::TexturedDraw()
{
	if(textureManager)
		textureManager->EnableTexture(textureIndex);
		
	glEnable(GL_TEXTURE_2D);
	glColor4f(1,1,1,1);
	int i = 0;
	glBegin(GL_POLYGON);
		List<Vertex> * search = vertices->head;
		while(search)
		{
			if(search->payload)
			{
				//printf("textureVertex = (%f, %f)\n", textureVertices[i].x, textureVertices[i].y);
				glTexCoord2f(textureVertices[i].x, textureVertices[i].y);
				glVertex2f(search->payload->GetPosition().x,search->payload->GetPosition().y);
				i++;	
			}
			search = search->next;
		}
		glEnd();
	glDisable(GL_TEXTURE_2D);
}
void ClosedObject::GetHoverGroup(Mouse * mouse, VertexList * group)
{
	printf("ClosedObject::GetHoverGroup\n");
	Vertex * left = NULL;
	Vertex * right = NULL;
	
	if(vertices)
	{
		vertices->GetHoverSegment(mouse, &left, &right);
	}
		

	if(left && right && group)
	{
		group->Add(left);
		group->Add(right);
		printf("HERE1\n");
	}
	else
	{
		if((mouse->GetWorldPosition() | position.GetPosition()) < 1)
		{
			printf("HERE2\n");
			group->Add(&position);
			List<Vertex> * search = vertices->head;
			while(search)
			{
				if(search->payload)
				{
					group->Add(search->payload);
				}
				search = search->next;
			}
		}		
	}
}
char * ClosedObject::GetTag()
{
	printf("Getting border tag\n");
	char * points = vertices->GetRelativeTag(position.GetPosition());
	char * positionTag = position.GetTag();
	char * materialName = material->name;
	char * tag = (char *)malloc(strlen(points)+strlen(positionTag)+strlen(materialName)+40);
	char * mass = propertyMenu->GetFormContent(0);
	printf("mass string = %s\n", mass);
	float m = 1.0;
	sscanf(mass, "%f", &m);
	if(m < 0.0)
		m = 1.0;
	sprintf(tag, "<object,baseobject,%s,%.3f,%d,%s,%s,0,%.1f>", materialName,textureRotation,vertices->GetLength(),points,positionTag,m);
	delete points;
	free(mass);
	return tag;	
}
bool ClosedObject::CheckObjectHover(Mouse * mouse)
{
	Vertex * vertex = vertices->GetHoverVertex(mouse);
	
	if(vertex || (mouse->GetWorldPosition() | position.GetPosition()) < 1)
	{
		activeObject = true;
	}
	else 
	{
		//check to see if we clicked inside the object
		//does a line from the mouse to the position cross an edge?
		List<Vertex> * left = vertices->head;
		if(Vector2D::SegmentsIntersect(vertices->head->payload->GetPosition(), vertices->tail->payload->GetPosition(), 
		   mouse->GetWorldPosition(), position.GetPosition()))
		{
			return activeObject = false;	
		}
		
		while(left && left->next)
		{	
			List<Vertex> * right = left->next;
			
			Vector2D leftPoint = left->payload->GetPosition();
			Vector2D rightPoint = right->payload->GetPosition();
			
			if(Vector2D::SegmentsIntersect(leftPoint, rightPoint, mouse->GetWorldPosition(), position.GetPosition()))
			{
				activeObject = false;
				return activeObject;
			}
			left = right;
		}
		activeObject = true;
	}
		
	return activeObject;	
}
Vector2D ClosedObject::GetRotationPoint()
{
	return position.GetPosition();
}
void ClosedObject::CalculatePosition()
{
	List<Vertex> * search = vertices->head;
	Vector2D center = Vector2D(0,0);
	int count = 0;
	while(search)
	{
		if(search->payload)
		{
			center = center + search->payload->GetPosition();
			count++;
		}
		search = search->next;
	}	
	center = center / count;
	position = center;
}
